#include "qobjecthost.h"

#include "qdatamanager.h"

#include "../../include/abstractproperty.h"
#include "../../include/qcommonstruct.h"
#include "qglobalobject.h"


#include <QScriptValue>
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QStringList>
#include <QMouseEvent>
#include <QMetaMethod>

static QMap<QString,QMap<QString,QString> > g_propertyObjectType;
static QMap<QString,QString> g_propertyType;

QObjectHost::QObjectHost(QWidget *wid):
    m_global_object(NULL),
    m_engine(new QScriptEngine),
    m_widget(wid)
{
    m_widget->installEventFilter(this);
    initProperty();
}

void QObjectHost::initProperty()
{
    addPropertyGroup(QStringList()<<"Attribute"<<"Events");
    addProperty("Attribute",QStringList()<<"objectName"<<"geometry"<<"memeryValue"
                <<"enabled"<<"cursor"<<"Z-Value"<<"toolTip"<<"visible");
    addProperty("Events",QStringList()<<"mousePressEvent"<<"mouseMoveEvent"<<"mouseRelessEvent"
                <<"mouseDbClickEvent");
    addUserProperty(QStringList()<<"enabled"<<"visible");
    m_widget->setProperty("host",int(this));
    m_widget->setProperty("Z-Value",1);
    m_widget->setProperty("StyleSheet_group",QStringList()<<"StyleSheet");
}

void QObjectHost::addPropertyGroup(const QStringList &groups)
{
    QStringList g=m_widget->property("designer_all_groups").toStringList();
    foreach(QString str,groups)
    {
        if(g.indexOf(str)<0)
        {
            g.append(str);
        }
    }
    m_widget->setProperty("designer_all_groups",g);
}

void QObjectHost::addStyleSheetGroup(const QStringList &groups)
{
    QStringList g=m_widget->property("StyleSheet_group").toStringList();
    foreach(QString str,groups)
    {
        if(g.indexOf(str)<0)
        {
            g.append(str);
        }
    }
    m_widget->setProperty("StyleSheet_group",g);
}

void QObjectHost::addProperty(const QString &group, const QStringList &propertys)
{
    QStringList g=m_widget->property("designer_all_groups").toStringList();
    if(g.indexOf(group)<0)
    {
        addPropertyGroup(QStringList()<<group);
    }
    QString str="designer_"+group;
    QStringList pro=m_widget->property(str.toLocal8Bit()).toStringList();
    foreach(QString s,propertys)
    {
        if(pro.indexOf(s)<0)
        {
            pro.append(s);
        }
    }
    m_widget->setProperty(str.toLocal8Bit(),pro);
}

void QObjectHost::addUserProperty(const QStringList &pro)
{
    QStringList g=m_widget->property("designer_user_property").toStringList();
    foreach(QString s,pro)
    {
        if(g.indexOf(s)<0)
        {
            g.append(s);
        }
    }
    m_widget->setProperty("designer_user_property",g);
}

void QObjectHost::initScript()
{
    QScriptValue glo=m_engine->newQObject(this);

    glo.setProperty("this",glo);

    m_engine->setGlobalObject(glo);
}

QObjectHost::~QObjectHost()
{
    delete m_engine;
}

void QObjectHost::initGlobalObject()
{
    initScript();
    QGlobalObject *global=QGlobalObject::globalObject();
    QMap<QString,QGraphicsProxyWidget*>  pages=global->pages();

    QMapIterator<QString,QGraphicsProxyWidget*> it(pages);
    while(it.hasNext())
    {
        it.next();
        QObjectHost *host=(QObjectHost*)(it.value()->widget()->property("host").toInt());
        if(host!=NULL)
        {
            QScriptValue v=m_engine->newQObject(host);

            QObjectList list=it.value()->widget()->children();
            foreach(QObject* o,list)
            {
                QObjectHost *h=(QObjectHost*)(o->property("host").toInt());
                if(h!=NULL)
                {
                    QScriptValue c=m_engine->newQObject(h);
                    v.setProperty(o->property("objectName").toString(),c);
                }
            }

            m_engine->globalObject().setProperty(it.key(),v);
        }

    }
}

void QObjectHost::setGlobalObject(QObject *o)
{
    QGlobalObject *global=QGlobalObject::globalObject();
    int c=global->metaObject()->methodCount();
    QString signal,slot;
    QStringList list;
    for(int i=0;i<c;i++)
    {
        QMetaMethod m=global->metaObject()->method(i);
        if(m.methodType()==QMetaMethod::Slot && m.signature()!=QString("deleteLater()") && m.signature()!=QString("_q_reregisterTimers(void*)"))
        {
            list.append(m.signature());
            signal=QString("2%1").arg(m.signature());
            slot=QString("1%1").arg(m.signature());
            connect(this,signal.toLocal8Bit(),global,slot.toLocal8Bit());
        }
    }


    c=this->metaObject()->methodCount();

    list.append("destroyed(QObject*)");
    list.append("destroyed()");
    for(int i=0;i<c;i++)
    {
        QMetaMethod m=this->metaObject()->method(i);
        if(m.methodType()==QMetaMethod::Signal)
        {
            if(list.indexOf(m.signature())<0)
            {
                signal=QString("2%1").arg(m.signature());
                slot=QString("1%1").arg(m.signature());
                connect(this,signal.toLocal8Bit(),m_widget,slot.toLocal8Bit());
            }
        }
    }
}

void QObjectHost::exec(const QString code, const QString &para)
{
    QStringList list=para.split(",");
    QStringList names;
    int index;
    QString name,value;
    if(list.size()>2)
    {
        for(int i=2;i<list.size();i++)
        {
            index=list.at(i).indexOf("=");
            if(index>=0)
            {
                name=list.at(i).left(index);
                value=list.at(i).mid(index+1);
                if(name!="" && value!="")
                {
                    QScriptValue v=m_engine->newVariant(value);
                    m_engine->globalObject().setProperty(name,v,QScriptValue::ReadOnly);
                    names.append(name);
                }
            }
        }
    }

    m_engine->evaluate(code);
    if(m_engine->hasUncaughtException())
    {
        qDebug(m_engine->uncaughtException().toString().toLocal8Bit());
    }
    foreach(QString str,names)
    {
        QScriptValue v=m_engine->newVariant(QVariant());
        m_engine->globalObject().setProperty(str,v,QScriptValue::ReadOnly);
    }
}

bool QObjectHost::eventFilter(QObject *o, QEvent *e)
{
    if(o==m_widget)
    {
        QMouseEvent *event=(QMouseEvent*)e;
        if(e->type()==QEvent::MouseButtonPress)
        {
            objectMousePress(event);
        }
        else if(e->type()==QEvent::MouseButtonRelease)
        {
            objectMouseRelease(event);
        }
        else if(e->type()==QEvent::MouseButtonDblClick)
        {
            objectMouseDbClick(event);
        }
        else if(e->type()==QEvent::MouseMove)
        {
            objectMouseMove(event);
        }
    }
    return QObject::eventFilter(o,e);
}

void QObjectHost::objectMousePress(QMouseEvent *e)
{
    QString code=m_widget->property("mousePressEvent").toString();
    if(code!="")
    {
        QString para=QString("type=mouseEvent,num=%1,_button=%2,_x=%3,_y=%4").arg(3).arg(e->button()).arg(e->pos().x()).arg(e->pos().y());
        exec(code,para);
    }
}

void QObjectHost::objectMouseRelease(QMouseEvent *e)
{
    QString code=m_widget->property("mouseRelessEvent").toString();
    if(code!="")
    {
        QString para=QString("type=mouseEvent,num=%1_button=%2,_x=%3,_y=%4").arg(3).arg(e->button()).arg(e->pos().x()).arg(e->pos().y());
        exec(code,para);
    }
}

void QObjectHost::objectMouseDbClick(QMouseEvent *e)
{
    QString code=m_widget->property("mouseDbClickEvent").toString();
    if(code!="")
    {
        QString para=QString("type=mouseEvent,num=%1,_button=%2,_x=%3,_y=%4").arg(3).arg(e->button()).arg(e->pos().x()).arg(e->pos().y());
        exec(code,para);
    }
}

void QObjectHost::objectMouseMove(QMouseEvent *e)
{
    QString code=m_widget->property("mouseMoveEvent").toString();
    if(code!="")
    {
        QString para=QString("type=mouseEvent,num=%1,_button=%2,_x=%3,_y=%4").arg(3).arg(e->button()).arg(e->pos().x()).arg(e->pos().y());
        exec(code,para);
    }
}

void QObjectHost::updatePropertyAttribute()
{
    PropertyList list=m_widget->property("property_list").value<PropertyList>();

    QString name;

    foreach(QAbstractProperty *p,list)
    {
        name=p->name();

        if(name=="geometry")
        {
            p->setAttribute("Width::min",1);
            p->setAttribute("Height::min",1);
            p->setAttribute("Width::max",0xfff);
            p->setAttribute("Height::max",0xfff);
        }
        else if(name=="font")
        {
            p->setAttribute("Point Size::min",1);
        }
        else if(name=="Z-Value")
        {
            p->setAttribute("min",1);
        }
        else if(name=="mousePressEvent" ||
                name=="mouseRelessEvent" ||
                name=="mouseDbClickEvent" ||
                name=="mouseMoveEvent")
        {
            p->setAttribute("param","mouseEvent");
        }
    }
}

void QObjectHost::initRunningProperty()
{
    connect(QDataManager::manager(),SIGNAL(userDataChanged(QString,QVariant)),this,SLOT(dataChanged(QString,QVariant)));
    MemeryValueItems items=m_widget->property("memeryValue").value<MemeryValueItems>();
    foreach(tagMemeryValueInfo info,items)
    {
        m_widget->setProperty(info.m_propertyName.toLocal8Bit(),QDataManager::manager()->userData(info.m_valueName));
    }
    QStringList l=m_widget->property("StyleSheet_group").toStringList();
    foreach(QString s,l)
    {
        QStringList ll=m_widget->property(("designer_"+s).toLocal8Bit()).toStringList();
        foreach(QString str,ll)
        {
            updateStyle(str,false);
        }
    }
    updateStyleSheet();
}

void QObjectHost::dataChanged(const QString &key, const QVariant &value)
{
    MemeryValueItems items=m_widget->property("memeryValue").value<MemeryValueItems>();
    foreach(tagMemeryValueInfo info,items)
    {
        if(key==info.m_valueName)
        {
            m_widget->setProperty(info.m_propertyName.toLocal8Bit(),value);
        }
    }
}

void QObjectHost::updateStyle(const QString &name, bool now)
{
    if(name=="color")
    {
        tagColorInfo c=m_widget->property(name.toLocal8Bit()).value<tagColorInfo>();
        QString str;
        if(c.m_type==0)
        {
            str="";
        }
        else
        {
            str=QString("#%1{").arg(m_widget->property("objectName").toString());
            str+=QString("background-color:rgba(%1,%2,%3,%4);")
                    .arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
            str+="}";
        }
        m_styleSheets.insert(name,str);
    }
    else if(name=="textColor")
    {
        tagColorInfo c=property(name.toLocal8Bit()).value<tagColorInfo>();
        QString str;
        if(c.m_type==0)
        {
            str="";
        }
        else
        {
            str=QString("#%1{").arg(m_widget->property("objectName").toString());
            str+=QString("color:rgba(%1,%2,%3,%4);")
                    .arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
            str+="}";
        }
        m_styleSheets.insert(name,str);
    }
    else if(name=="disabled textColor")
    {
        tagColorInfo c=m_widget->property(name.toLocal8Bit()).value<tagColorInfo>();
        QString str;
        if(c.m_type==0)
        {
            str="";
        }
        else
        {
            str=QString("#%1:disabled{").arg(m_widget->property("objectName").toString());
            str+=QString("color:rgba(%1,%2,%3,%4);")
                    .arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
            str+="}";
        }
        m_styleSheets.insert(name,str);
    }
    else if(name=="hover textColor")
    {
        tagColorInfo c=m_widget->property(name.toLocal8Bit()).value<tagColorInfo>();
        QString str;
        if(c.m_type==0)
        {
            str="";
        }
        else
        {
            str=QString("#%1:hover{").arg(m_widget->property("objectName").toString());
            str+=QString("color:rgba(%1,%2,%3,%4);")
                    .arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
            str+="}";
        }
        m_styleSheets.insert(name,str);
    }
    else if(name=="pressed textColor")
    {
        tagColorInfo c=m_widget->property(name.toLocal8Bit()).value<tagColorInfo>();
        QString str;
        if(c.m_type==0)
        {
            str="";
        }
        else
        {
            str=QString("#%1:pressed{").arg(m_widget->property("objectName").toString());
            str+=QString("color:rgba(%1,%2,%3,%4);")
                    .arg(c.m_color.red()).arg(c.m_color.green()).arg(c.m_color.blue()).arg(c.m_color.alpha());
            str+="}";
        }
        m_styleSheets.insert(name,str);
    }
    else if(name=="image")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();

        if(info.m_name!="")
        {
            setImageSheet(name,&info,"");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="disabled image")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();

        if(info.m_name!="")
        {
            setImageSheet(name,&info,":disabled");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="hover image")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();

        if(info.m_name!="")
        {
            setImageSheet(name,&info,":hover");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="pressed image")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();

        if(info.m_name!="")
        {
            setImageSheet(name,&info,":pressed");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="unchecked normal")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:unchecked");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="unchecked hover")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:unchecked:hover");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="unchecked disabled")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:unchecked:disabled");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="unchecked pressed")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:unchecked:pressed");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="checked normal")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:checked");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="checked hover")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:checked:hover");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="checked disabled")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:checked:disabled");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="checked pressed")
    {
        tagImageInfo info=m_widget->property(name.toLocal8Bit()).value<tagImageInfo>();
        if(info.m_name!="")
        {
            setImageSheet(name,&info,"::indicator:checked:pressed");
        }
        else
        {
            m_styleSheets.remove(name);
        }
    }
    else if(name=="padding")
    {
        tagPaddingInfo padding=property(name.toLocal8Bit()).value<tagPaddingInfo>();
        QString str;
        str=QString("#%1{").arg(m_widget->property("objectName").toString());
        str+=QString("padding-left:%1;padding-top:%2;padding-right:%3;padding-bottom:%4")
                .arg(padding.m_left).arg(padding.m_top).arg(padding.m_right).arg(padding.m_bottom);
        str+="}";
        m_styleSheets.insert(name,str);
    }
    else if(name=="border")
    {
        tagBorderInfo border=property(name.toLocal8Bit()).value<tagBorderInfo>();
        if(!border.m_isNull)
        {
            QString str;
            str=QString("#%1{").arg(m_widget->property("objectName").toString());
            str+=QString("border:%1px %2 rgba(%3,%4,%5,%6)")
                    .arg(border.m_border_width).arg(border.m_border_type)
                    .arg(border.m_color.red()).arg(border.m_color.green())
                    .arg(border.m_color.blue()).arg(border.m_color.alpha());
            str+="}";
            m_styleSheets.insert(name,str);
        }
    }
    if(now)
    {
        updateStyleSheet();
    }
}

void QObjectHost::setImageSheet(const QString &name, tagImageInfo *info, const QString &type)
{
    QString str=QString("#%1%2{").arg(m_widget->property("objectName").toString()).arg(type);
    if(info->m_type==1)
    {
        str+=QString("border-image:url(:/soft_res/%1)%2 %3 %4 %5;").arg(info->m_name).arg(info->m_top).arg(info->m_bottom).arg(info->m_right).arg(info->m_left);
    }
    else
    {
        str+=QString("%1:url(:/soft_res/%2);").arg(info->m_type==0?"image":"background-image").arg(info->m_name);
    }
    str+="}";
    m_styleSheets.insert(name,str);
}

bool QObjectHost::visible()
{
    return m_widget->isVisible();
}

bool QObjectHost::enabled()
{
    return m_widget->isEnabled();
}

void QObjectHost::setProperty(const QString &name, const QVariant &value)
{
    m_widget->setProperty(name.toLocal8Bit(),value);
}

QVariant QObjectHost::property(const QString &name)
{
    return m_widget->property(name.toLocal8Bit());
}

int QObjectHost::x()
{
    return m_widget->x();
}

int QObjectHost::y()
{
    return m_widget->y();
}

int QObjectHost::width()
{
    return m_widget->width();
}

int QObjectHost::height()
{
    return m_widget->height();
}

void QObjectHost::setGeomerty(int x, int y, int width, int height)
{
    m_widget->setGeometry(x,y,width,height);
}

void QObjectHost::setToolTip(const QString &tooltip)
{
    m_widget->setToolTip(tooltip);
}

QString QObjectHost::toolTip()
{
    return m_widget->toolTip();
}

void QObjectHost::updateStyleSheet()
{
    QString str;
    QMapIterator<QString,QString>   it(m_styleSheets);
    while(it.hasNext())
    {
        it.next();
        if(it.value()!="")
        {
            str+=it.value();
        }
    }
    m_widget->setStyleSheet(str);
}

void qRegPropertyType(const QString &type, const QString &name, const QString &className)
{
    if(className=="")
    {
        g_propertyType.insert(name,type);
    }
    else
    {
        QMap<QString,QString> p=g_propertyObjectType.value(className);
        p.insert(name,type);
        g_propertyObjectType.insert(className,p);
    }
}

QString propertyType(const QString &name, const QString &className)
{
    QMap<QString,QString> p=g_propertyObjectType.value(className);
    if(p.contains(name))
    {
        return p.value(name);
    }
    else
    {
        return g_propertyType.value(name,"QIntProperty");
    }
}
